好啦,經過前一天對於自動化測試和測試金字塔的探討,我們準備好可以開始真正動手寫程式了 XD
今天我們會用VSCode開發環境,使用 Go 語言來打造 RSS 閱讀器的 API。
VSCode是個相當方便、功能多樣的編輯器,對Go語言也有很棒的支持。你可以從官網下載VSCode,然後再從其擴充功能市集安裝 Go 語言的支援套件。
當然也不要忘記去 Go 的官網下載 Go 語言的安裝檔,並且設定好環境變數。
建立一個資料夾,並初始化 go mod
mkdir MyGoProject
cd MyGoProject
go mod init github.com/yourusername/too-simple-rss-reader
初始化後,你會在專案資料夾中看到一個 go.mod
檔案。這個檔案將用於管理你的 Go 專案依賴。
現在,新增一個名為 main.go
的檔案。這個檔案將作為我們專案的入口點。為了快速展示一個最小可行的例子,我們先編寫一個簡單的 code。
package main
import (
"encoding/json"
"fmt"
"net/http"
"sync"
"time"
"github.com/mmcdole/gofeed"
)
type Feed struct {
URL string `json:"url"`
Read bool `json:"read"`
Items []FeedItem `json:"items"`
}
type FeedItem struct {
Title string `json:"title"`
Link string `json:"link"`
Read bool `json:"read"`
}
var (
feedMap = make(map[string]Feed)
feedMapMutex = &sync.RWMutex{}
)
func subscribeFeed(w http.ResponseWriter, r *http.Request) {
var feed Feed
err := json.NewDecoder(r.Body).Decode(&feed)
if err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
fp := gofeed.NewParser()
parsedFeed, err := fp.ParseURL(feed.URL)
if err != nil {
http.Error(w, "Invalid RSS URL", http.StatusBadRequest)
return
}
feed.Items = make([]FeedItem, len(parsedFeed.Items))
for i, item := range parsedFeed.Items {
feed.Items[i] = FeedItem{Title: item.Title, Link: item.Link, Read: false}
}
feedMapMutex.Lock()
feedMap[feed.URL] = feed
feedMapMutex.Unlock()
json.NewEncoder(w).Encode(feed)
}
func listSubscribedFeeds(w http.ResponseWriter, r *http.Request) {
feedMapMutex.RLock()
defer feedMapMutex.RUnlock()
feeds := make([]Feed, 0, len(feedMap))
for _, feed := range feedMap {
feeds = append(feeds, feed)
}
json.NewEncoder(w).Encode(feeds)
}
func deleteFeed(w http.ResponseWriter, r *http.Request) {
var feed Feed
err := json.NewDecoder(r.Body).Decode(&feed)
if err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
feedMapMutex.Lock()
delete(feedMap, feed.URL)
feedMapMutex.Unlock()
// Return an empty feed to indicate success
json.NewEncoder(w).Encode(Feed{})
}
func markItemRead(w http.ResponseWriter, r *http.Request) {
var payload struct {
URL string `json:"url"`
Title string `json:"title"`
Read bool `json:"read"`
}
err := json.NewDecoder(r.Body).Decode(&payload)
if err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
feedMapMutex.Lock()
defer feedMapMutex.Unlock()
feed, ok := feedMap[payload.URL]
if !ok {
http.Error(w, "Feed not found", http.StatusBadRequest)
return
}
for i, item := range feed.Items {
if item.Title == payload.Title {
feed.Items[i].Read = payload.Read
break
}
}
feedMap[payload.URL] = feed
// Return the updated feed to indicate success
json.NewEncoder(w).Encode(feed)
}
func updateFeeds() {
fp := gofeed.NewParser()
feedMapMutex.Lock()
for url, feed := range feedMap {
parsedFeed, err := fp.ParseURL(url)
if err != nil {
fmt.Printf("Error parsing feed %s: %v\n", url, err)
continue
}
existingItems := make(map[string]bool)
for _, item := range feed.Items {
existingItems[item.Title] = true
}
for _, newItem := range parsedFeed.Items {
if _, exists := existingItems[newItem.Title]; !exists {
feed.Items = append(feed.Items, FeedItem{Title: newItem.Title, Link: newItem.Link, Read: false})
}
}
feedMap[url] = feed
}
feedMapMutex.Unlock()
}
func autoUpdateFeeds() {
ticker := time.NewTicker(10 * time.Minute)
for range ticker.C {
updateFeeds()
}
}
func main() {
http.HandleFunc("/subscribe", subscribeFeed)
http.HandleFunc("/list", listSubscribedFeeds)
http.HandleFunc("/delete", deleteFeed)
http.HandleFunc("/markRead", markItemRead)
go autoUpdateFeeds()
http.ListenAndServe(":8080", nil)
}
本專案提供了一個基本的 RSS 閱讀器 API,它能夠幫助你更有效地管理和瀏覽你喜愛的 RSS feeds。一旦成功啟動服務,透過訪問 http://localhost:8080/
,你將能夠接觸到以下核心功能:
在我們的基本架構確定之後,我們還有很多事情可以做:
今天我們初步建立了RSS閱讀器的基礎架構,包括一個簡單的Go語言API和前端HTML頁面。在接下來的幾天,我們將逐步增加更多功能和測試。
希望你會喜歡這次的內容,如果你有什麼問題或建議,隨時可以告訴我喔!謝謝!